// 堆操作异常行为分析	设计并完成算法，记录并给出提示：
// 1.检测堆申请与释放是否一致（正常）；
// 2.是否发生重复的多次释放（异常）
// 文件操作异常行为分析	设计并完成算法，记录并给出提示：
// 1.	判断操作范围是否有多个文件夹；
// 2.	是否存在自我复制的情况；
// 3.	是否修改了其它可执行代码包括exe，dll，ocx等；
// 4.	是否将文件内容读取后发送到网络（选做）；
// 注册表操作异常行为分析	设计并完成算法，记录并给出提示：
// 1.	判断是否新增注册表项并判断是否为自启动执行文件项；
// 2.	是否修改了注册表；
// 3.	输出所有的注册表操作项；

//导入所有状态码
import STATUSCODE from './statusCode';

export interface OperationData{
  type: string,
  hook_type: string,
  api_name: string,
  timestamp: string,
  args: {
    //MessageBox
    hWnd?:string,
    lpCaption?:string,
    lpText?:string,
    uType?:string,
    //HeapCreate
    HANDLE?:string,
    dwInitialSize?:string,
    dwMaximumSize?:string,
    fIOoptions?:string,
    //HeapAlloc,HeapFree
    hHeap?:string,
    dwFlags?:string,
    lpMem?:string,
    //CreateDirectory,CreateDirectoryA
    lpPathName?:string,
    //CreateFile
    lpFileName?:string,
    dwDesiredAccess?:string,
    dwShareMode?:string,
    lpSecurityAttributes?:string,
    dwCreationDisposition?:string,
    dwFlagsAndAttributes?:string,
    hTemplateFile?:string,
    //ReadFile,WriteFile
    hFile?:string,
    lpBuffer?:string,
    nNumberOfBytesToRead?:string,
    lpNumberOfBytesRead?:string,
    nNumberOfBytesToWrite?:string,
    lpNumberOfBytesWritten?:string,
    lpOverlapped?:string,
    MD5?:string,
    //RegOpenKeyEx
    hKey?:string,
    lpSubKey?:string,
    ulOptions?:string,
    samDesired?:string,
    phkResult?:string,
    //RegDeleteKeyEX
    Reserved?:string,
    //RegQueryValueEx
    lpValueName?:string,
    lpReserved?:string,
    lpType?:string,
    lpData?:string,
    lpcbData?:string,
    //RegSetValueEx
    dwType?:string,
    cbData?:string,
  }
}

interface Status{
  code: number,
  message: string
}

export interface StatusArray{
  status: Status[]
}

export interface BadgeNum{
  trace:{
    normal:number,
    warning:number,
    danger:number
  },
  messageBox:{
    normal:number,
    warning:number,
    danger:number
  },
  heap:{
    normal:number,
    warning:number,
    danger:number
  },
  file:{
    normal:number,
    warning:number,
    danger:number
  },
  registry:{
    normal:number,
    warning:number,
    danger:number
  },
  socket:{
    normal:number,
    warning:number,
    danger:number
  }
}

export interface FileInfo{
  fileName:string,
  fileHandle:string
}

export interface ProcessInfo{
  processPathName:string|undefined,
  processID:number,
  threadID:number
}


const mobitorMessageBoxOperation = (data: OperationData) => {
  let statusArray:StatusArray = {status:[]};
  switch (data.api_name) {
    case 'MessageBoxA':
      statusArray.status.push({code:100,message:STATUSCODE.STATUSCODE_100});
      break;
    case 'MessageBoxW':
      statusArray.status.push({code:101,message:STATUSCODE.STATUSCODE_101});
      break;
  }
  return statusArray;
}

const monitorHeapOperation = (data: OperationData,heapAllocArray:string[],heapFreeArray:string[]) => {
  // 1.检测堆申请与释放是否一致（正常）；
  // 2.是否发生重复的多次释放（异常）
  //先设置两个数组，一个用于存放堆申请的地址，一个用于存放堆释放的地址
  //当申请时，将地址存入堆申请数组中
  //当释放时，检查地址是否存在于堆申请数组中，以及是否存在堆释放数组中
  //如果存在于堆释放数组中，则说明发生了重复释放，如果不存在于堆申请数组中，则说明申请与释放不一致
  let statusArray:StatusArray = {status:[]};
  switch (data.api_name) {
    case 'HeapAlloc':
      heapAllocArray.push(data.args.hHeap!);
      statusArray.status.push({code:121,message:STATUSCODE.STATUSCODE_121});
      break;
    case 'HeapFree':
      statusArray.status.push({code:122,message:STATUSCODE.STATUSCODE_122});
      if(heapFreeArray.indexOf(data.args.hHeap!) != -1){
        console.log('重复释放');
        statusArray.status.push({code:300,message:STATUSCODE.STATUSCODE_300});
      }
      if(heapAllocArray.indexOf(data.args.hHeap!) == -1){
        statusArray.status.push({code:201,message:STATUSCODE.STATUSCODE_201});
      }
      heapFreeArray.push(data.args.hHeap!);
      break;
    case 'HeapCreate':
      statusArray.status.push({code:120,message:STATUSCODE.STATUSCODE_120});
      break;
    case 'HeapDestroy':
      statusArray.status.push({code:123,message:STATUSCODE.STATUSCODE_123});
      break;
  }
  return statusArray;
}

const monitorFileOperation = (data: OperationData,processPathName:string,fileInfoArray:FileInfo[],folderArray:string[]) => {
  // 1.	判断操作范围是否有多个文件夹；
  // 2.	是否存在自我复制的情况；
  // 3.	是否修改了其它可执行代码包括exe，dll，ocx等；
  // 4.	是否将文件内容读取后发送到网络（选做）；
  let statusArray:StatusArray = {status:[]};
  switch (data.api_name) {
    case 'CreateDirectoryA':
    case 'CreateDirectory':
      statusArray.status.push({code:114,message:STATUSCODE.STATUSCODE_114});
      folderArray.push(data.args.lpPathName!);
      if(folderArray.length > 1){
        statusArray.status.push({code:200,message:STATUSCODE.STATUSCODE_200});
      }
      break;
    case 'CreateFileA':
    case 'CreateFile':
      statusArray.status.push({code:110,message:STATUSCODE.STATUSCODE_110});
      const filePathName = data.args.lpFileName;
      const fileName = filePathName?.split('\\').pop();
      //文件后缀
      const fileSuffix = fileName?.split('.').pop();
      console.log('fileName:',fileName);
      console.log('fileSuffix:',fileSuffix);
      if(fileSuffix === 'exe' || fileSuffix === 'dll' || fileSuffix === 'ocx'){
        statusArray.status.push({code:302,message:STATUSCODE.STATUSCODE_302});
      }
      console.log('processPathName:',processPathName);
      console.log('filePathName:',filePathName);
      //判断是否自我复制
      const processName = processPathName?.split('\\').pop();
      console.log('processName:',processName);
      if(fileName === processName){
        statusArray.status.push({code:301,message:STATUSCODE.STATUSCODE_301});
      }
      fileInfoArray.push({fileName:fileName!,fileHandle:data.args.HANDLE!});
      break;
    case 'OpenFile':
      statusArray.status.push({code:111,message:STATUSCODE.STATUSCODE_111});
      break;
    case 'ReadFile':
      statusArray.status.push({code:112,message:STATUSCODE.STATUSCODE_112});
      break;
    case 'WriteFile':
      statusArray.status.push({code:113,message:STATUSCODE.STATUSCODE_113});
      //判断写入文件的类型是否为exe，dll，ocx
      const fileHandle = data.args.hFile;
      const fileInfo = fileInfoArray.find((item) => item.fileHandle === fileHandle);
      if(fileInfo){
        const fileName = fileInfo.fileName;
        const fileSuffix = fileName.split('.').pop();
        if(fileSuffix === 'exe' || fileSuffix === 'dll' || fileSuffix === 'ocx'){
          statusArray.status.push({code:302,message:STATUSCODE.STATUSCODE_302});
        }
      }
      break;
  }
  return statusArray;
}

const monitorRegistryOperation = (data: OperationData) => {
  // 1.	判断是否新增注册表项并判断是否为自启动执行文件项；
  // 2.	是否修改了注册表；
  // 3.	输出所有的注册表操作项；
  let statusArray:StatusArray = {status:[]};
  switch (data.api_name) {
    case 'RegCreateKeyEx':
      statusArray.status.push({code:136,message:STATUSCODE.STATUSCODE_136});
      statusArray.status.push({code:203,message:STATUSCODE.STATUSCODE_203});
      break;
    case 'RegOpenKeyEx':
      statusArray.status.push({code:130,message:STATUSCODE.STATUSCODE_130});
      //判断是否为自启动执行文件项
      const subKey = data.args.lpSubKey;
      if(subKey === 'Software\\Microsoft\\Windows\\CurrentVersion\\Run'){
        statusArray.status.push({code:303,message:STATUSCODE.STATUSCODE_303});
      }
      break;
    case 'RegCloseKey':
      statusArray.status.push({code:131,message:STATUSCODE.STATUSCODE_131});
      break;
    case 'RegDeleteKeyEx':
      statusArray.status.push({code:132,message:STATUSCODE.STATUSCODE_132});
      statusArray.status.push({code:203,message:STATUSCODE.STATUSCODE_203});
      break;
    case 'RegQueryValueEx':
      statusArray.status.push({code:133,message:STATUSCODE.STATUSCODE_133});
      console.log('query');
      break;
    case 'RegSetValueEx':
      statusArray.status.push({code:134,message:STATUSCODE.STATUSCODE_134});
      statusArray.status.push({code:203,message:STATUSCODE.STATUSCODE_203});
      console.log('set');
      break;
    case 'RegDeleteValue':
      statusArray.status.push({code:135,message:STATUSCODE.STATUSCODE_135});
      statusArray.status.push({code:203,message:STATUSCODE.STATUSCODE_203});
      console.log('delete');
      break;
  }
  return statusArray;
}

//@ts-ignore
const monitorNetworkOperation = (data: OperationData) => {
  // 1.	判断是否有网络连接；
  // 2.	是否有数据发送；
  // 3.	是否有数据接收；
  // 4.	是否有数据发送到特定的IP地址；
  if (data.api_name === 'send') {
    console.log('send');
  } else {
    console.log('receive');
  }
}


export const monitorOperation = (data: OperationData,props) => {
    let {heapAllocArray,heapFreeArray,fileInfoArray,processPathName,folderArray} = props;
    let statusArray:StatusArray = {status:[]};
    switch (data.hook_type) {
      case 'MessageBox':
        statusArray = mobitorMessageBoxOperation(data);
        break;
      case 'Heap':
        statusArray = monitorHeapOperation(data,heapAllocArray,heapFreeArray);
        break;
      case 'File':
        statusArray = monitorFileOperation(data,processPathName,fileInfoArray,folderArray);
        break;
      case 'Registry':
        statusArray = monitorRegistryOperation(data);
        break;
      // case 'Socket':
      //   monitorNetworkOperation(data);
      //   break;
    }
    return {statusArray,heapAllocArray,heapFreeArray,fileInfoArray,folderArray};
}


export const calculateBadgeNum = (statusArray:StatusArray,type:string,badgeNum:BadgeNum) => {
  let newBadgeNum = badgeNum;
  switch (type) {
    case 'MessageBox':
      statusArray.status.map((item) => {
        if(item.code >= 100 && item.code < 200) {
          newBadgeNum.messageBox.normal = newBadgeNum.messageBox.normal + 1;
        } else if(item.code >= 200 && item.code < 300) {
          newBadgeNum.messageBox.warning = newBadgeNum.messageBox.warning + 1;
        } else if(item.code >= 300 && item.code < 400) {
          newBadgeNum.messageBox.danger = newBadgeNum.messageBox.danger + 1;
        }
      })
      break;
    case 'Heap':
      statusArray.status.map((item) => {
        if(item.code >= 100 && item.code < 200) {
          newBadgeNum.heap.normal = newBadgeNum.heap.normal + 1;
        } else if(item.code >= 200 && item.code < 300) {
          newBadgeNum.heap.warning = newBadgeNum.heap.warning + 1;
        } else if(item.code >= 300 && item.code < 400) {
          newBadgeNum.heap.danger = newBadgeNum.heap.danger + 1;
        }
      })
      break;
    case 'File':
      statusArray.status.map((item) => {
        if(item.code >= 100 && item.code < 200) {
          newBadgeNum.file.normal = newBadgeNum.file.normal + 1;
        } else if(item.code >= 200 && item.code < 300) {
          newBadgeNum.file.warning = newBadgeNum.file.warning + 1;
        } else if(item.code >= 300 && item.code < 400) {
          newBadgeNum.file.danger = newBadgeNum.file.danger + 1;
        }
      })
      break;
    case 'Registry':
      statusArray.status.map((item) => {
        if(item.code >= 100 && item.code < 200) {
         newBadgeNum.registry.normal = newBadgeNum.registry.normal + 1;
        } else if(item.code >= 200 && item.code < 300) {
          newBadgeNum.registry.warning = newBadgeNum.registry.warning + 1;
        } else if(item.code >= 300 && item.code < 400) {
          newBadgeNum.registry.danger = newBadgeNum.registry.danger + 1;
        }
      })
      break;
    case 'Socket':
      statusArray.status.map((item) => {
        if(item.code >= 100 && item.code < 200) {
          newBadgeNum.socket.normal = newBadgeNum.socket.normal + 1;
        } else if(item.code >= 200 && item.code < 300) {
          newBadgeNum.socket.warning = newBadgeNum.socket.warning + 1;
        } else if(item.code >= 300 && item.code < 400) {
          newBadgeNum.socket.danger = newBadgeNum.socket.danger + 1;
        }
      })
      break;
  }
  statusArray.status.map((item) => {
    if(item.code >= 100 && item.code < 200) {
      newBadgeNum.trace.normal = newBadgeNum.trace.normal + 1;
    }else if(item.code >= 200 && item.code < 300) {
      newBadgeNum.trace.warning = newBadgeNum.trace.warning + 1;
    }else if(item.code >= 300 && item.code < 400) {
      newBadgeNum.trace.danger = newBadgeNum.trace.danger + 1;
    }
})
console.log('newBadgeNum:',newBadgeNum);
return newBadgeNum;
}
